* Testing the frontend-maven-plugin

This is a maven project that is a testbed for delivering [[https://reactjs.org][react.js]] frontends from apache karaf.

The [[https://github.com/steinarb/frontend-karaf-demo/blob/master/pom.xml#L138][maven plugin config]]:
 - uses [[https://github.com/eirslett/frontend-maven-plugin][frontend-maven-plugin]] to [[https://webpack.js.org][webpack]] a  [[https://reactjs.org][react.js]] application into a self-contained bundle.js file that can be served as a static resource. Note that this doesn't need a node.js installed when building, nor will it use any node.js/npm installed locally on the build machine.
   The [[https://github.com/eirslett/frontend-maven-plugin][frontend-maven-plugin]] will download and upack its own node.js, and use this node.js to download the npm dependencies and create the bundle.js
 - uses [[http://felix.apache.org/components/bundle-plugin/][maven-bundle-plugin]] to create two DS OSGi components that expose the Servlet service that is plugged into an OSGi web whiteboard
   1. The DS component ReactServlet serves the static resources index.html and bundle.js on the path "/frontend-karaf-demo"
   2. The DS component IncrementerServlet receives POST requests on  the path "/frontend-karaf-demo/api/increment", parses the POSTed JSON into a bean, increments the value property of the bean, and returns the bean as a JSON object (ie. the servlet is stateless and just increments the value of the POSTed object)
 - uses [[https://karaf.apache.org/manual/latest/#_using_the_karaf_maven_plugin][karaf-maven-plugin]] to create an [[https://karaf.apache.org/manual/latest/#_features_repositories_2][apache karaf feature repository]] that loads the servlets and ensures that all runtime requirements are in place (the pax web whiteboard extender, the jackson JSON parser). The feature repository is attached to the maven bundle artifact

The react application uses the following features:
 - [[https://reactjs.org][react.js]] to render the application's page
 - [[https://redux.js.org][redux]] to hold the application's state
 - [[https://redux-toolkit.js.org][Redux Toolkit]] to create redux actions and reducers (if a reducer is longer than a single line per action your redux state is probably organized wrong)
 - [[https://redux-saga.js.org][redux-saga]] and [[https://github.com/axios/axios][axios]] for REST API communication and asynchronous update of the application's state
 - [[https://reacttraining.com/react-router/][react-router]] to route between different pages (however this requires hardcoding the ReactServlet's path into the react app, and requires the ReactServlet to return the top level index.html from all routes)

The react application follows the structure I've found clear and easy to work with:
 - Avoid embedding binaries like images or fonts in the bundle.js, it's better to load them from a web resource
 - Avoid embedding large CSS files like e.g. bootstrap in bundle.js, again: it's better to load them from a web resource
 - The build script and package.json in the top directory with the application in a subdirectory named =src/=
 - Inside =src/=
   - On the top, index.js that enters the application and sets up and starts redux and saga
   - actiontypes.js containing all of the redux actions in the applcation, created using redux toolkit's "[[https://redux-toolkit.js.org/api/createAction][createAction()]]"
   - Subdirectory =components/= containing all of the visible UI components of the frontend app
     - Note in particular Counter.js which demonstrates both displaying data from redux and dispatching actions with redux
   - Subdirectory =reducers/= containing all of the reducers (created with redux toolkit "[[https://redux-toolkit.js.org/api/createReducer#usage-with-the-map-object-notation][createReducer()]] using the map notation, and using "computed syntax" (i.e. square brackets on property identifiers), to be able to use the createAction() actions directly
   - Subdirectory =sagas/= containing the sagas that handle asynchronous REST API communication (a REST operation is triggered by dispatching a redux action that is picked up by the saga, and both successful and failed REST responses results in redux actions, that in turn are picked up by reducers and stored in the reduc state

** Status

[[https://github.com/steinarb/frontend-karaf-demo/actions/workflows/frontend-karaf-demo-maven-ci-build.yml][file:https://github.com/steinarb/frontend-karaf-demo/actions/workflows/frontend-karaf-demo-maven-ci-build.yml/badge.svg]]
[[https://coveralls.io/github/steinarb/frontend-karaf-demo][file:https://coveralls.io/repos/github/steinarb/frontend-karaf-demo/badge.svg]]
[[https://sonarcloud.io/summary/new_code?id=steinarb_frontend-karaf-demo][file:https://sonarcloud.io/api/project_badges/measure?project=steinarb_frontend-karaf-demo&metric=alert_status#.svg]]
[[https://maven-badges.herokuapp.com/maven-central/no.priv.bang.demos/frontend-karaf-demo][file:https://maven-badges.herokuapp.com/maven-central/no.priv.bang.demos/frontend-karaf-demo/badge.svg]]

[[https://sonarcloud.io/summary/new_code?id=steinarb_frontend-karaf-demo][file:https://sonarcloud.io/images/project_badges/sonarcloud-white.svg]]

[[https://sonarcloud.io/summary/new_code?id=steinarb_frontend-karaf-demo][file:https://sonarcloud.io/api/project_badges/measure?project=steinarb_frontend-karaf-demo&metric=sqale_index#.svg]]
[[https://sonarcloud.io/summary/new_code?id=steinarb_frontend-karaf-demo][file:https://sonarcloud.io/api/project_badges/measure?project=steinarb_frontend-karaf-demo&metric=coverage#.svg]]
[[https://sonarcloud.io/summary/new_code?id=steinarb_frontend-karaf-demo][file:https://sonarcloud.io/api/project_badges/measure?project=steinarb_frontend-karaf-demo&metric=ncloc#.svg]]
[[https://sonarcloud.io/summary/new_code?id=steinarb_frontend-karaf-demo][file:https://sonarcloud.io/api/project_badges/measure?project=steinarb_frontend-karaf-demo&metric=code_smells#.svg]]
[[https://sonarcloud.io/summary/new_code?id=steinarb_frontend-karaf-demo][file:https://sonarcloud.io/api/project_badges/measure?project=steinarb_frontend-karaf-demo&metric=sqale_rating#.svg]]
[[https://sonarcloud.io/summary/new_code?id=steinarb_frontend-karaf-demo][file:https://sonarcloud.io/api/project_badges/measure?project=steinarb_frontend-karaf-demo&metric=security_rating#.svg]]
[[https://sonarcloud.io/summary/new_code?id=steinarb_frontend-karaf-demo][file:https://sonarcloud.io/api/project_badges/measure?project=steinarb_frontend-karaf-demo&metric=bugs#.svg]]
[[https://sonarcloud.io/summary/new_code?id=steinarb_frontend-karaf-demo][file:https://sonarcloud.io/api/project_badges/measure?project=steinarb_frontend-karaf-demo&metric=vulnerabilities#.svg]]
[[https://sonarcloud.io/summary/new_code?id=steinarb_frontend-karaf-demo][file:https://sonarcloud.io/api/project_badges/measure?project=steinarb_frontend-karaf-demo&metric=duplicated_lines_density#.svg]]
[[https://sonarcloud.io/summary/new_code?id=steinarb_frontend-karaf-demo][file:https://sonarcloud.io/api/project_badges/measure?project=steinarb_frontend-karaf-demo&metric=reliability_rating#.svg]]

*** Branches

| branch        | karaf version | snapshot version | OSGi version |
|---------------+---------------+------------------+--------------|
| master        |         4.3.x | 2.0.0-SNAPSHOT   | OSGi 7       |
| release/1.1.0 |        4.2.11 | 1.1.0-SNAPSHOT   | OSGi 6       |

** Installation on apache karaf

Installation steps:
 1. Clone this project and build it:
    #+BEGIN_EXAMPLE
      mkdir -p ~/git
      cd ~/git/
      git clone https://github.com/steinarb/frontend-karaf-demo.git
      cd ~/git/frontend-karaf-demo/
      mvn clean install
    #+END_EXAMPLE
 2. Install apache karaf (e.g. [[https://karaf.apache.org/manual/latest/quick-start.html][according to the karaf quick start guide]] or by [[https://steinar.bang.priv.no/2018/01/23/packaging-karaf-with-native-debian-packaging-tools/][installing the .deb package on debian/ubuntu/raspbian]]), and start karaf
 3. From the karaf console (either from the karaf started above, or from an SSH session into a running karaf), install the application with the following commands:
    #+BEGIN_EXAMPLE
      feature:repo-add mvn:no.priv.bang.demos/frontend-karaf-demo/LATEST/xml/features
      feature:install frontend-karaf-demo
    #+END_EXAMPLE
 4. Open a web browser on http://localhost:8181/frontend-karaf-demo/ and use the "+" and "-" buttons to increment and decrement the counter
    - If using Chrome or Chromium it's a good idea to press Ctrl-Shift-i to open the developer tools, where it is possible to watch error messages in the console, and set breakpoints and debug the JavaScript code
    - It's also a good idea to visit the [[https://chrome.google.com/webstore/category/extensions][Chrome Web Store]] and install:
      1. [[https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi][React Developer Tools]] from Facebook
         - The "React" tab in chrome devtools gives a view of the react application tree, rather than the DOM, where it is possible to examine the react components' props and state, it's also possible to click on a part of the application and navigate to the corret place in the react application tree
      2. [[https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd][Redux DevTools]] from remotedevio
         - The "Redux" tab in chrome devtools lets you examine the redux store of the application

** LICENSE

This maven project is licensed under Apache v2.0.

See the file LICENSE for details.
